package lambda;

import java.lang.reflect.Array;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class TheStream {
    public static void main(String[] args) {
        /**
         * Stream中间操作
         */
        //StreamForEcach();//forEach()
        //StreamFilter();//filter()
        //StreamLimit();//limit()
        //StreamSkip();//skip()
        //StreamDistinct();//distinct()
        //StreamMap();//map()
        //StreamSorted();//sorted


        /**
         * Stream终止操作
         */
        //StreamAllMatch();//allMatch()
        // StreamMaxMin();//Max()和 Min()
        //StreamSumAve();//sum()和 average()

        //StreamGroupingOrderBy();
        StreamConvert();//

    }

    /**
     * Stream中间操作 1.forEach()
     * 循环每一个元素
     */
    public static void StreamForEcach(){
        /**
         * 数组
         */
        System.out.println("--------------------数组的forEach()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        Arrays.stream(nums).forEach(n->{
            //用forEach()遍历数组无法获取下标
            System.out.println("n = "+n);
        });


        /**
         * List
         */
        System.out.println("--------------------List的forEach()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懒羊羊");
        list.stream().forEach(l->{
            System.out.println("index = "+list.indexOf(l)+"    value = "+l);
        });

        /**
         * map
         */
        System.out.println("-------------------Map的forEach()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懒羊羊");

        //map遍历方式1
        System.out.println("map遍历方式1：");
        map.keySet().forEach(key -> {
            System.out.println("key : "+key+"    value : "+map.get(key));
        });

        //map遍历方式2
        System.out.println("map遍历方式2：");
        map.entrySet().forEach(entry -> {
            System.out.println("key : " + entry.getKey() + "    value : " + entry.getValue());
        });

        //map遍历方式3
        System.out.println("map遍历方式3:");
        map.forEach((key,value)->{
            System.out.println("key : "+key+"    value : "+value);
        });

        /**
         * set
         */
        System.out.println("--------------------set的forEach()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        set.forEach(s->{
            System.out.println(s);
        });
    }

    /**
     * Stream中间操作 2.filter()
     * 过滤筛选出符合某些条件的项，filter(条件 && 条件)
     */
    public static void StreamFilter(){
        /**
         * 数组
         */
        System.out.println("--------------------数组的filter()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //筛选出除了10的所有偶数
        int[] newNums = Arrays.stream(nums).filter(n -> (n % 2 == 0 && n != 10)).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的filter()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懒羊羊");
        //筛选出以"羊"结尾的项
        List<String> newList = list.stream().filter(l -> l.endsWith("羊")).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的filter()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懒羊羊");
        //通过以狼结尾的项筛选出灰太狼
        Map<String, String> newMap = map.entrySet().stream().filter(m -> {
            if (m.getKey().startsWith("狼") && m.getValue().equals("灰太狼")) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的filter()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //筛选出偶数
        Set<Integer> newSet = set.stream().filter(s -> s % 2 == 0).collect(Collectors.toSet());
        newSet.forEach(System.out::println);

    }

    /**
     * Stream中间操作 3.limit()
     * 它是用于限制流中元素的个数，即取前n个元素，返回新的流
     */
    public static void StreamLimit(){
        /**
         * 数组
         */
        System.out.println("--------------------数组的limit()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //取出前10个数
        int[] newNums = Arrays.stream(nums).limit(5).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的limit()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懒羊羊");
        //取出前两项
        List<String> newList = list.stream().limit(2).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的limit()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懒羊羊");
        //取出前两项
        Map<String, String> newMap = map.entrySet().stream().limit(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的limit()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //取出前两项
        Set<Integer> newSet = set.stream().limit(2).collect(Collectors.toSet());
        newSet.forEach(System.out::println);

    }

    /**
     * Stream中间操作 4.skip()
     * 该方法与limit()方法互补
     * skip()方法用于跳过前面n个元素，然后再返回新的流
     */
    public static void StreamSkip(){

        /**
         * 方法skip(n)的参数n的四种情况：
         *
         * （1）当n<0时，抛IllegalArgumentException异常；
         *
         * （2）当n=0时，相当没有跳过任何元素，原封不动、完璧归赵；
         *
         * （3）当0<n<length时，跳过n个元素后，返回含有剩下的元素的流；
         *
         * （4）当n>=length时，跳过所有元素，返回空流。
         */


        /**
         * 数组
         */
        System.out.println("--------------------数组的skip()--------------------");
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        //跳过前5项返回其余的项
        int[] newNums = Arrays.stream(nums).skip(5).toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的skip()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("小灰灰");
        list.add("懒羊羊");
        ////跳过前2项返回其余的项
        List<String> newList = list.stream().skip(2).collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map
         */
        System.out.println("--------------------Map的skip()--------------------");
        Map<String,String> map = new HashMap<>();
        map.put("狼1","灰太狼");
        map.put("狼2","小灰灰");
        map.put("羊1","喜羊羊");
        map.put("羊2","懒羊羊");
        //跳过前2项返回其余的项
        Map<String, String> newMap = map.entrySet().stream().skip(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));

        newMap.forEach((k,v)->{
            System.out.println("key = "+k+"     value = "+v);
        });

        /**
         * set
         */
        System.out.println("--------------------Set的skip()--------------------");
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        //跳过前2项返回其余的项
        Set<Integer> newSet = set.stream().skip(2).collect(Collectors.toSet());
        newSet.forEach(System.out::println);
    }

    /**
     * Stream中间操作 5.distinct()
     * 去除重复项
     */
    public static void StreamDistinct(){
        /**
         * 数组
         */
        System.out.println("--------------------数组的distinct()--------------------");
        int[] nums = {1,2,3,1,2,34,4,5,5,8,4};
        //去除重复项
        int[] newNums = Arrays.stream(nums).distinct().toArray();
        Arrays.stream(newNums).forEach(System.out::println);

        /**
         * List
         */
        System.out.println("--------------------List的distinct()--------------------");
        List<String> list = new ArrayList<>();
        list.add("灰太狼");
        list.add("灰太狼");
        list.add("喜羊羊");
        list.add("喜羊羊");
        list.add("懒羊羊");
        //去除重复项
        List<String> newList = list.stream().distinct().collect(Collectors.toList());
        newList.forEach(System.out::println);

        /**
         * map和set因为不可重复性所以没必要用到distinct()
         */

    }

    /**
     * Stream中间操作 6.map()
     * 可以将对象转换为其他对象
     * Stream.map()是Stream最常用的一个转换方法，它把一个Stream转换为另一个Stream
     * 所谓map操作，就是把一种操作运算，映射到一个序列的每一个元素上。
     * 例如，对x计算它的平方，可以使用函数f(x) = x * x。我们把这个函数映射到一个序列1，2，3，4，5上，就得到了另一个序列1，4，9，16，25：
     */
    public static void StreamMap(){
        //将数组先转为Stream,再平方后再转为数组
        int[] nums = {1, 2, 3, 4, 5};
        int[] result1 = Arrays.stream(nums)
                .map(n -> n * n)
                .toArray();

        //将Strings列表转换为大写
        List<String> list1 = Arrays.asList("a","b","c","d","e");
        List<String> newList1 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
        newList1.forEach(System.out::println);


        //对象列表 - >字符串列表
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
                );
        List<String> newUsers = users.stream().map(u -> u.getName()).collect(Collectors.toList());
        newUsers.forEach(System.out::println);


        //对象列表 - >其他对象列表(User  ->  Account)
        List<Account> accounts = users.stream().map(u -> {
            Account account = new Account();
            account.setId(u.getId());
            account.setName(u.getName());
            return account;
        }).collect(Collectors.toList());
        accounts.forEach(System.out::println);


    }

    /**
     * Stream中间操作 7.sorted()
     * 排序
     */
    public static void StreamSorted(){
        //将数组先转为Stream,再平方后再转为数组
        int[] nums = {11, 2, 32, 14, 5};
        int[] newNums = Arrays.stream(nums).sorted().toArray();
        Arrays.stream(newNums).forEach(System.out::println);



        //按对象的年龄排序
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        List<User> newUsers = users.stream().sorted((p1, p2) -> {
            return p1.getAge().compareTo(p2.getAge());
        }).collect(Collectors.toList());
        newUsers.forEach(System.out::println);


    }

    /**
     * Stream终止操作 1.allMatch()
     * 检查是否匹配所有元素
     */
    public static void StreamAllMatch(){
        //判断数组的元素是否都是在0-20之间
        int[] nums = {11, 2, 32, 14, 5};
        boolean isBetweenZeroTwenty = Arrays.stream(nums).allMatch(n -> (n >= 0) && (n <= 20));
        System.out.println("数组的元素是否都是在0-20之间:"+isBetweenZeroTwenty);


        //判断user列表的元素的年纪是否都是大于等于18岁
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        boolean isAdult  = users.stream().allMatch(u -> u.getAge() >= 18);
        System.out.println("user列表的元素的年纪是否都是大于等于18岁:"+isAdult);
    }

    /**
     * Stream终止操作 2.max()和 min()
     * 查找最大值
     */
    public static void StreamMaxMin(){
        //返回数组最大值
        int[] nums = {11, 2, 32, 14, 5};
        int numMax = Arrays.stream(nums).max().getAsInt();
        int numMin = Arrays.stream(nums).min().getAsInt();
        System.out.println("数组最大值："+numMax);
        System.out.println("数组最小值："+numMin);

        //返回年纪最大值
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        Optional<User> userMax = users.stream().max((p, q) -> {
            return p.getAge().compareTo(q.getAge());
        });

        Optional<User> userMin = users.stream().min((p, q) -> {
            return p.getAge().compareTo(q.getAge());
        });
        System.out.println("年纪最大的是 : "+userMax.get());
        System.out.println("年纪最小的是 : "+userMin.get());

    }

    /**
     * Stream终止操作 3.sum()和 average()
     * 查找最大值
     */
    public static void StreamSumAve(){
        //求和与平均值
        int[] nums = {11, 2, 32, 14, 5};
        int numSum = Arrays.stream(nums).sum();//求和
        double numAve = Arrays.stream(nums).average().getAsDouble();//求平均值
        System.out.println("求和 ："+numSum);
        System.out.println("平均值："+numAve);

        //对象的求和与平均值
        List<User> users = Arrays.asList(
                new User(1,"灰太狼",new Date(),11,"男"),
                new User(2,"喜羊羊",new Date(),10,"男"),
                new User(3,"小灰灰",new Date(),15,"男")
        );
        Integer userAgeSum = users.stream().map(u -> u.getAge()).reduce(Integer::sum).get();
        Double userAgeAve = users.stream().collect(Collectors.averagingInt(p -> p.getAge()));


        System.out.println("用户年纪求和 : "+userAgeSum);
        System.out.println("用户年纪平均值 : "+userAgeAve);

    }


    /**
     * Stream高级应用 1.排序并分组
     *
     */
    public static void StreamGroupingOrderBy(){
        try {
            SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
            //对象的求和与平均值
            List<User> users = Arrays.asList(
                    new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
                    new User(2,"红太狼",simFormat.parse("2018/01/23"),10,"女"),
                    new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
                    new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
                    new User(3,"懒羊羊",simFormat.parse("2020/02/13"),15,"男")
            );

            //按性别分组
            Map<String, List<User>> collectSex = users.stream()
                    .sorted(Comparator.comparing(User::getBirthday))
                    .collect(Collectors.groupingBy(User::getSex));
            //输出
            collectSex.forEach((k,v)->{
                System.out.println("key : "+k+"    value : "+v);
            });
            //按出生日期的day分组
            Map<Date, List<User>> collectBirthday= users.stream()
                    .sorted(Comparator.comparing(User::getBirthday))
                    .collect(Collectors.groupingBy(u->u.getBirthday()));

            //输出
            collectBirthday.forEach((k,v)->{
                System.out.println("key : "+simFormat.format(k)+"    value : "+v);
            });




        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stream高级应用 2.集合之间转换
     *
     */
    public static void StreamConvert(){


        try {
            /**
             * List  ---->  Map
             */
            SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
            List<User> users = Arrays.asList(
                    new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
                    new User(2,"红太狼",simFormat.parse("2018/01/23"),10,"女"),
                    new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
                    new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
                    new User(3,"懒羊羊",simFormat.parse("2020/02/13"),15,"男")
            );

            //以name为key,age为value,将list<User>转为Map
            Map<String, Integer> map = users.stream().collect(Collectors.toMap(User::getName, User::getAge));
           map.forEach((key,value)->{
               System.out.println("key:"+key+"    value:"+value);
           });



            /**
             * List  ----->  Set
             */
            Set<User> collect1 = users.stream().collect(Collectors.toSet());
            collect1.forEach(System.out::println);


            /**
             * Map  ----->  List
             */
            List<String> stringList = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toList());
            stringList.forEach(System.out::println);

            /**
             * Map  ---->  Set
             */
            Set<String> stringSet = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toSet());
            stringSet.forEach(System.out::println);


            /**
             * Set  ---->  List
             */
            List<String> list = stringSet.stream().collect(Collectors.toList());
            list.forEach(System.out::println);

        } catch (ParseException e) {
            e.printStackTrace();
        }




    }




}


class User{
    private Integer id;
    private String name;
    private Date birthday;
    private Integer age;
    private String sex;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public User(Integer id, String name, Date birthday, Integer age, String sex) {
        this.id = id;
        this.name = name;
        this.birthday = birthday;
        this.age = age;
        this.sex = sex;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Date getBirthday() {
        return birthday;
    }
}
class Account {
    private Integer id;
    private String name;

    public Account() {
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Account(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
